function degToRad(angle)
{
  return angle * (Math.PI / 180.0);
}


function Vector2(x,y)
{
  this.x = x;
  this.y = y;
}

function $V(x,y)
{
  return new Vector2(x,y);
}

Vector2.prototype.add = function (v)
{
  return $V(this.x + v.x,this.y + v.y);
}

Vector2.prototype.sub = function (v)
{
  return $V(this.x - v.x,this.y - v.y);
}

Vector2.prototype.neg = function ()
{
  return $V(-this.x,-this.y);
}

Vector2.prototype.abs = function ()
{
  return $V(Math.abs(this.x),Math.abs(this.y));
}

Vector2.prototype.min = function (v)
{
  return $V(Math.min(this.x,v.x),Math.min(this.y,v.y));
}

Vector2.prototype.max = function (v)
{
  return $V(Math.max(this.x,v.x),Math.max(this.y,v.y));
}

Vector2.prototype.mul = function (v)
{
  if(v instanceof Vector2)
    return $V(this.x * v.x,this.y * v.y);
  else
    return $V(this.x * v, this.y * v);
}

Vector2.prototype.div = function (v)
{
  if(v instanceof Vector2)
    return $V(this.x / v.x,this.y / v.y);
  else
    return $V(this.x / v, this.y / v);
}

Vector2.prototype.clone = function ()
{
  return $V(this.x,this.y);
}

Vector2.prototype.round = function ()
{
  return $V(Math.round(this.x),Math.round(this.y));
}

Vector2.prototype.floor = function ()
{
  return $V(Math.floor(this.x),Math.floor(this.y));
}

function Vector3(x,y,z)
{
  this.x = x;
  this.y = y;
  this.z = z;
}

function Matrix22()
{
  this._00 = 1;
  this._10 = 0;
  this._01 = 0;
  this._11 = 1;
}

// Data specified in Row first ie.
//  +--------+
//  | 00, 10 | 
//  | 01, 11 |
//  +--------+
//
//  [00,10,01,11]

Matrix22.prototype.specify = function (data)
{
  this._00 = data[0];
  this._10 = data[1];
  this._01 = data[2];
  this._11 = data[3];  
}

Matrix22.prototype.rotational = function (angle)
{
  this._11 = this._00 = Math.cos(angle);
  this._01 = Math.sin(angle);
  this._10 = -this._01;
  
  return this;
}

Matrix22.prototype.mul = function (v)
{
  if(v instanceof Vector2)
  {
    //00  10 \/  X = 00 x X + 10 x Y 
    //01  11 /\  Y = 01 X X + 11 X Y    
    return $V(this._00 * v.x + this._10 * v.y, this._01 * v.x + this._11 * v.y);
  } else
    throw new Error('not implemented data type');
}

function Matrix33()
{
  this._00 = 1;
  this._10 = 0;
  this._20 = 0;
  this._01 = 0;
  this._11 = 1;  
  this._21 = 0;
  this._02 = 0;
  this._12 = 0;
  this._22 = 1;
}

// Data specified in Row first ie.
//  +------------+
//  | 00, 10, 20 | 
//  | 01, 11, 21 |
//  | 02, 12, 22 |
//  +------------+
//
//  [00,10,20,01,11,21,02,12,22]

Matrix33.prototype.specify = function (data)
{
  this._00 = data[0];
  this._10 = data[1];
  this._20 = data[2];
  this._01 = data[3];
  this._11 = data[4];
  this._21 = data[5];
  this._02 = data[6];
  this._12 = data[7];
  this._22 = data[8];
}

Matrix33.prototype.mul = function (obj)
{
  if(obj instanceof Vector2)
    return this.mul(new Vector3(obj.x,obj.y,1));
  else if(obj instanceof Vector3)
  {
//  +------------+      +---+     +---------------------+     
//  | 00, 10, 20 |      | X |     | 00xX + 10xY + 20xZ  |
//  | 01, 11, 21 |   \/ | Y |  =  | 01xX + 11xY + 21xZ  |
//  | 02, 12, 22 |   /\ | Z |     | 02xX + 12xY + 22xZ  |
//  +------------+      +---+     +---------------------+
    
    return new Vector3( this._00 * obj.x + this._10 * obj.y + this._20 * obj.z,
                        this._01 * obj.x + this._11 * obj.y + this._21 * obj.z,
                        this._02 * obj.x + this._12 * obj.y + this._22 * obj.z);
  } else if (obj instanceof Matrix33)
  {
    var data = [(this._00 * obj._00 + this._10 * obj._01 + this._20 * obj._02),
                (this._00 * obj._10 + this._10 * obj._11 + this._20 * obj._12),
                (this._00 * obj._20 + this._10 * obj._21 + this._20 * obj._22),
                (this._01 * obj._00 + this._11 * obj._01 + this._21 * obj._02),
                (this._01 * obj._10 + this._11 * obj._11 + this._21 * obj._12),
                (this._01 * obj._20 + this._11 * obj._21 + this._21 * obj._22),
                (this._02 * obj._00 + this._12 * obj._01 + this._22 * obj._02),
                (this._02 * obj._10 + this._12 * obj._11 + this._22 * obj._12),
                (this._02 * obj._20 + this._12 * obj._21 + this._22 * obj._22)];
    var m = new Matrix33();
    m.specify(data);
    return m;
  }
}

Matrix33.prototype.toString = function ()
{
  return  '[['+this._00+', '+this._10+', '+this._20+']\n'+
          ' ['+this._01+', '+this._11+', '+this._21+']\n'+
          ' ['+this._02+', '+this._12+', '+this._22+']]';
}

Matrix33.prototype.rotate = function (angle)
{  
  this._11 = this._00 = Math.cos(angle);
  this._01 = Math.sin(angle);
  this._10 = -this._01;
  
  return this;
}

Matrix33.prototype.translate = function (point)
{  
  this._20 = point.x;
  this._21 = point.y;
  
  return this;
}

Matrix33.prototype.scale = function (scale)
{
  this._00 = scale.x;
  this._11 = scale.y;
  
  return this;
}


Matrix33.prototype.clone = function ()
{
  var m = new Matrix33();
  m._00 = this._00;
  m._01 = this._01;
  m._02 = this._02;
  m._10 = this._10;
  m._11 = this._11;
  m._12 = this._12;
  m._20 = this._20;
  m._21 = this._21;
  m._22 = this._22;
  return m;
}

function rand(min,max)
{
  return Math.floor(rand_f(max,min,false));
}

function rand_f(min,max)
{
  return min + (Math.random() * (max-min));
}

function range(min,max,value)
{
  return value >= min && value <= max;
}